package com.idroc.coelacanth.service.servant.bdb;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.idroc.coelacanth.core.storage.Cursor;
import com.idroc.coelacanth.core.storage.Record;
import com.idroc.coelacanth.core.storage.support.KeyValueWrapperRecord;
import com.idroc.coelacanth.core.storage.support.KeyValues;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

public class BerkeleyCursor implements Cursor {

	private static final Logger log = LoggerFactory.getLogger(BerkeleyCursor.class);
	
	private com.sleepycat.je.Database bdb = null;
	private com.sleepycat.je.CursorConfig cc = null;
	private com.sleepycat.je.Cursor cursor = null;
	
	BerkeleyCursor(Database db) {
		this.bdb = db;
	}

	public void close() {
		
		try {
			cursor.close();
		} catch (DatabaseException ex) {
			log.error("关闭游标异常", ex);
			throw new RuntimeException(ex);
		}
	}

	public long count() {

		try {
			return cursor.count();
		} catch (DatabaseException ex) { 
			log.error("游标计算记录数异常", ex);
			throw new RuntimeException(ex);
		} 
	}

	public boolean deleteCurrent() { 
		
		OperationStatus os = null;
		try {
			os = cursor.delete();
		} catch (DatabaseException ex) {
			log.error("游标删除当前记录异常", ex);
			throw new RuntimeException(ex);
		}
		return os == OperationStatus.SUCCESS;
	}

	public Record getCurrent() {

		DatabaseEntry k = new DatabaseEntry();
		DatabaseEntry v = new DatabaseEntry();
		OperationStatus os = null;
		try {
			os = cursor.getCurrent(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取当前记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {			
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public Record getFirst() {
		
		DatabaseEntry k = new DatabaseEntry();
		DatabaseEntry v = new DatabaseEntry();
		OperationStatus os = null;
		try {
			os = cursor.getFirst(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取第一条记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {			
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public Record getLast() {

		DatabaseEntry k = new DatabaseEntry();
		DatabaseEntry v = new DatabaseEntry();
		OperationStatus os = null;
		try {
			os = cursor.getLast(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取最后记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {			
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public Record getNext() {

		DatabaseEntry k = new DatabaseEntry();
		DatabaseEntry v = new DatabaseEntry();
		OperationStatus os = null;
		try {
			os = cursor.getNext(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取下一条记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {			
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public Record getPrev() {

		DatabaseEntry k = new DatabaseEntry();
		DatabaseEntry v = new DatabaseEntry();
		OperationStatus os = null;
		try {
			os = cursor.getPrev(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取上一条记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {			
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public void open() {
		
		cc = new CursorConfig();
	    cc.setReadCommitted(true);
	    try {
			cursor = bdb.openCursor(null, cc);
		} catch (DatabaseException ex) {
			log.error("数据库打开游标异常", ex);
			throw new RuntimeException(ex);
		}
	}

	public boolean saveCurrent(Record r) {

		DatabaseEntry v = new DatabaseEntry(r.getValue().getBytes());
		OperationStatus os = null;
		try {
			os = cursor.putCurrent(v);
		} catch (DatabaseException ex) {
			log.error("游标保存当前记录异常", ex);
			throw new RuntimeException(ex);
		}
		return (os == OperationStatus.SUCCESS);
	}

	public Record closeTo(Record r) {

		DatabaseEntry k = new DatabaseEntry(r.getKey().getBytes()); 
		DatabaseEntry v = new DatabaseEntry(); 
		OperationStatus os = null;
		try {
			os = cursor.getSearchKeyRange(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取最接近记录中key的记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

	public Record locateTo(Record r) {

		DatabaseEntry k = new DatabaseEntry(r.getKey().getBytes()); 
		DatabaseEntry v = new DatabaseEntry(); 
		OperationStatus os = null;
		try {
			os = cursor.getSearchKey(k, v, LockMode.DEFAULT);
		} catch (DatabaseException ex) {
			log.error("游标获取指定key的记录异常", ex);
			throw new RuntimeException(ex);
		}
		if (os == OperationStatus.SUCCESS) {
			return new KeyValueWrapperRecord(KeyValues.newStringKey(k.getData()), KeyValues.newByteArrayValue(v.getData()));
		} else {
			return null;
		}
	}

}
